# Copyright (c) 2025 Joshua Wise
# SPDX-License-Identifier: GPL-3.0-or-later

# Add tools directory to path
import sys
sys.path.append('../../../tools')

import json, re, os, waflib, sys, string, subprocess, tempfile
import pbpack
import polib
from collections import OrderedDict

from resources.resource_map.resource_generator_font import FontResourceGenerator

def make_lang(ctx):
    lang_code = waflib.Options.options.lang
    lang_path = os.path.join(ctx.path.abspath(), lang_code)
    pot_path = os.path.abspath('build/src/fw/tintin.pot');
    if not os.path.exists(pot_path):
        waflib.Logs.pprint('RED', 'Error: could not find tintin.pot. Please run ./waf build first')
        return
    po_path = os.path.join(lang_path, 'tintin.po')
    msginit_cmd = ['msginit', '-l', lang_code, '--no-translator', '-i', pot_path]
    if not os.path.exists(lang_path):
        # create folders and init po file from template
        os.mkdir(lang_path)
        with open(os.path.join(lang_path, "lang_map.json"), "w") as f:
            f.write(FILE_LANG_MAP.substitute({'lang': lang_code}))

    if not os.path.exists(po_path):
        msginit_cmd += ['-o', po_path]
        subprocess.call(msginit_cmd)
    else:
        # Save the existing po file header
        po_file_header_entry = polib.pofile(po_path).metadata_as_entry()
        po_file_header = str(po_file_header_entry)

        # Empty the po file and write back the header
        with open(po_path, 'w') as po_file:
            po_file.write(po_file_header)

        # Generate the new po file and merge it with the existing file
        new_po_file = tempfile.NamedTemporaryFile(delete=True)
        msginit_cmd += ['-o', new_po_file.name]
        subprocess.call(msginit_cmd)
        subprocess.call(['msgmerge', '--lang=' + lang_code, '--update', po_path, new_po_file.name])

def pack_all_langs(ctx):
    language_codes = next(os.walk(ctx.path.abspath()))[1]

    for language_code in language_codes:
        if not os.path.exists(os.path.join(ctx.path.abspath(), language_code, 'lang_map.json')):
            waflib.Logs.pprint('RED', f"Language code {language_code} does not have a lang_map.json (Crowdin import without metadata?); skipping.")
            continue
        pack_lang_code(ctx, language_code)

def pack_lang(ctx):
    lang_code = waflib.Options.options.lang
    pack_lang_code(ctx, lang_code)

def pack_lang_code(ctx, lang_code):
    lang_path = os.path.join(ctx.path.abspath(), lang_code)
    build_path = os.path.join(ctx.path.get_bld().abspath(), lang_code)

    resource_path = os.path.join(lang_path, 'lang_map.json')
    resource_map = json.loads(open(resource_path, mode='r').read());

    resource_data = OrderedDict()

    if not os.path.exists(build_path):
        os.makedirs(build_path)

    # Handle the "strings" object. Has the attributes "lang", "name", and "file".
    # We need to write the first entry into our pbpack for the .mo file
    strings = resource_map['strings']
    name = strings['name']

    if strings['file'] == "":
        # No .mo file?
        resource_data[name] = b''
    else:
        po_path = os.path.join(lang_path, strings['file'])

        # Check that the file contains no untranslated strings
        if subprocess.check_output(['msgattrib', '--untranslated', po_path]) != '':
            waflib.Logs.pprint('RED', 'Warning: This PO file contains untranslated strings!')

        # Save a few bytes in the .mo file by removing metadata that
        # shouldn't be there -- and, if the .po file came from Crowdin, it
        # might be missing its Name: metadata, so put that back.
        po_internal_path = os.path.join(build_path, strings['file'] + '.' + name + '.po')
        po = polib.pofile(po_path)

        if 'translation_name' in resource_map:
            po.metadata['Name'] = resource_map['translation_name']

        # PebbleOS FW wants a number here, but Crowdin puts in "pebbleos".
        if po.metadata.get('Project-Id-Version', 'pebbleos') == 'pebbleos':
            po.metadata['Project-Id-Version'] = '31337'

        allowed_keys = {
            'Project-Id-Version',
            'Language',
            'Name',
            'Content-Type',
            'Language-Team',
            'POT-Creation-Date',
            'PO-Revision-Date',
        }
        po.metadata = dict((k, v) for k, v in po.metadata.items() if k in allowed_keys)

        po.save(po_internal_path)

        mo_path = os.path.join(build_path, strings['file'] + '.' + name + '.mo')
        os.system('msgfmt -c -v -o {} {}'.format(mo_path, po_internal_path))

        waflib.Logs.pprint('CYAN', 'Created mo at {}'.format(mo_path))

        with open(mo_path, 'rb') as f:
            resource_data[name] = f.read()

        ui_codepoints_path = os.path.join(build_path, 'codepoints.json')
        os.system('python {} {} --output={}'.format('tools/generate_codepoint_requirements.py', po_path, ui_codepoints_path))

    # Generate a resource for each entry in the "fonts" list.
    for entry in resource_map['fonts']:
        name = entry['name']

        if 'alias' in entry:
            # Aliased resource
            # Handle aliases here by copying the data and adding it to the pbpack multiple times,
            # as the pbpack will handle the deduplication.
            waflib.Logs.pprint('CYAN', 'Aliasing {} to {}'.format(entry['alias'], name))

            resource_data[name] = resource_data[entry['alias']]
        elif entry['file'] == '':
            # Empty resource, just write an empty resource to the pbpack
            waflib.Logs.pprint('CYAN', 'Building empty resource {}'.format(name))

            resource_data[name] = b''
        else:
            # Finally, a real font resource! Generate it using the same tools as our normal
            # resource build.
            waflib.Logs.pprint('CYAN', 'Building font resource {}'.format(name))

            # Make the lang_map.json look more like the usual resource_map.json file format
            entry['type'] = 'font'

            # Normally definitions_from_dict returns a list to handle entries that define multiple
            # resources, but we only ever expect to get one definition per entry here.
            d = FontResourceGenerator.definitions_from_dict(ctx, entry, '')[0]

            if d.character_list is None:
                # By default, we only include codepoints needed for the UI, but it can be overridden
                d.character_list = ui_codepoints_path
            else:
                d.character_list = os.path.join(lang_path, d.character_list)

            # Now build the font data
            font_path = os.path.join(lang_path, entry['file'])
            font_data = FontResourceGenerator.build_font_data(font_path, d)
            resource_data[name] = font_data


    # Now write all the resource data to a pbpack
    lp = pbpack.ResourcePack(False)

    for r in resource_data.values():
        lp.add_resource(r)

    language_pack = os.path.join(build_path, lang_code + '.pbl')
    with open(language_pack, 'wb+') as lp_file:
        lp.serialize(lp_file)

    waflib.Logs.pprint('CYAN', 'Created language pack at {}'.format(language_pack))

FILE_LANG_MAP = string.Template("""
{
    "strings": {
        "lang": "${lang}",
        "name": "STRINGS",
        "file": "tintin.po"
    },
    "fonts": [{
        "name": "GOTHIC_14_EXTENDED",
        "file": ""
    }, {
        "name": "GOTHIC_14_BOLD_EXTENDED",
        "file": ""
    }, {
        "name": "GOTHIC_18_EXTENDED",
        "file": ""
    }, {
        "name": "GOTHIC_18_BOLD_EXTENDED",
        "file": ""
    }, {
        "name": "GOTHIC_24_EXTENDED",
        "file": ""
    }, {
        "name": "GOTHIC_24_BOLD_EXTENDED",
        "file": ""
    }, {
        "name": "GOTHIC_28_EXTENDED",
        "file": ""
    }, {
        "name": "GOTHIC_28_BOLD_EXTENDED",
        "file": ""
    }, {
        "name": "BITHAM_18_LIGHT_SUBSET_EXTENDED",
        "file": ""
    }, {
        "name": "BITHAM_30_BLACK_EXTENDED",
        "file": ""
    }, {
        "name": "BITHAM_34_LIGHT_SUBSET_EXTENDED",
        "file": ""
    }, {
        "name": "BITHAM_34_MEDIUM_NUMBERS_EXTENDED",
        "file": ""
    }, {
        "name": "BITHAM_42_BOLD_EXTENDED",
        "file": ""
    }, {
        "name": "BITHAM_42_LIGHT_EXTENDED",
        "file": ""
    }, {
        "name": "BITHAM_42_MEDIUM_NUMBERS_EXTENDED",
        "file": ""
    }, {
        "name": "ROBOTO_CONDENSED_21_EXTENDED",
        "file": ""
    }, {
        "name": "ROBOTO_BOLD_SUBSET_49_EXTENDED",
        "file": ""
    }, {
        "name": "DROID_SERIF_28_BOLD_EXTENDED",
        "file": ""
    }],
    "images": []
}
""")

# vim:filetype=python
